<template>
  <div ref="containerRef" :class="`${prefixCls}-container`">
    <a-upload :headers="headers" :multiple="multiple" :action="uploadUrl" :fileList="fileList" :disabled="disabled" :remove="onRemove" v-bind="bindProps" @change="onFileChange" @preview="onFilePreview">
      <template v-if="isImageMode">
        <div v-if="!isMaxCount">
          <Icon icon="ant-design:plus-outlined" />
          <div class="ant-upload-text">{{ text }}</div>
        </div>
      </template>
      <a-button v-else-if="buttonVisible" :disabled="isMaxCount || disabled">
        <Icon icon="ant-design:upload-outlined" />
        <span>{{ text }}</span>
      </a-button>
    </a-upload>
  </div>
</template>

<script lang="ts" setup>
import { ref, reactive, computed, watch, nextTick, createApp } from 'vue';
import { Icon } from '@components/common';
import { context } from '@pkg/request/bridge';
const { uploadUrl } = getGlobalConfig();
import { useMessage } from '@/hooks/web/useMessage';
import { useAttrs } from '@pkg/use';
import { useDesign } from '@/hooks/web/useDesign';
import { getFileAccessHttpUrl, getRandom } from '@pkg/utils';
import UploadItemActions from './base/UploadItemActions.vue';
import { UploadTypeEnum } from '../types/upload.data';
import { getGlobalConfig } from '@/internal';
const { createMessage, createConfirm } = useMessage();
const { prefixCls } = useDesign('file-upload');
const attrs = useAttrs();
const emit = defineEmits(['change', 'update:value']);
const props = defineProps({
  value: {
    type: [String, Array],
  },
  text: {
    type: String,
    default: '上传',
  },
  fileType: {
    type: String,
    default: 'all',
  },
  /*这个属性用于控制文件上传的业务路径*/
  bizPath: {
    type: String,
    default: 'temp',
  },
  /**
   * 是否返回url，
   * true：仅返回url
   * false：返回fileName filePath fileSize
   */
  returnUrl: {
    type: Boolean,
    default: true,
  },
  // 最大上传数量
  maxCount: {
    type: Number,
    default: 1,
  },
  buttonVisible: {
    type: Boolean,
    default: true,
  },
  multiple: {
    type: Boolean,
    default: true,
  },
  // 是否显示左右移动按钮
  mover: {
    type: Boolean,
    default: true,
  },
  // 是否显示下载按钮
  download: {
    type: Boolean,
    default: true,
  },
  // 删除时是否显示确认框
  removeConfirm: {
    type: Boolean,
    default: false,
  },
  beforeUpload: {
    type: Function,
  },
  disabled: {
    type: Boolean,
    default: false,
  },
});

const token = context.getTokenFunction?.();
//token
const headers = ref<object>({
  Authorization: token,
});
const fileList = ref<any[]>([]);
const uploadGoOn = ref<boolean>(true);
// refs
const containerRef = ref();
// 是否达到了最大上传数量
const isMaxCount = computed(() => props.maxCount > 0 && fileList.value.length >= props.maxCount);
// 当前是否是上传图片模式
const isImageMode = computed(() => props.fileType === UploadTypeEnum.image);
// 合并 props 和 attrs
const bindProps = computed(() => {
  const bind: any = Object.assign({}, props, attrs);
  bind.name = 'file';
  bind.listType = isImageMode.value ? 'picture-card' : 'text';
  bind.class = [bind.class, { 'upload-disabled': props.disabled }];
  bind.data = { biz: props.bizPath, ...bind.data };
  //自定义beforeUpload return false，并不能中断上传过程
  if (!bind.beforeUpload) {
    bind.beforeUpload = onBeforeUpload;
  }
  // 如果当前是图片上传模式，就只能上传图片
  if (isImageMode.value && !bind.accept) {
    bind.accept = 'image/*';
  }
  return bind;
});

watch(
  () => props.value,
  (val) => {
    if (Array.isArray(val)) {
      if (props.returnUrl) {
        parsePathsValue(val.join(','));
      } else {
        parseArrayValue(val);
      }
    } else {
      parsePathsValue(val);
    }
  },
  { immediate: true },
);

watch(fileList, () => nextTick(() => addActionsListener()), { immediate: true });

const antUploadItemCls = 'ant-upload-list-item';

// Listener
function addActionsListener() {
  if (!isImageMode.value) {
    return;
  }
  const uploadItems = containerRef.value ? containerRef.value.getElementsByClassName(antUploadItemCls) : null;
  if (!uploadItems || uploadItems.length === 0) {
    return;
  }
  for (const uploadItem of uploadItems) {
    let hasActions = uploadItem.getAttribute('data-has-actions') === 'true';
    if (!hasActions) {
      uploadItem.addEventListener('mouseover', onAddActionsButton);
    }
  }
}

// 添加可左右移动的按钮
function onAddActionsButton(event) {
  const getUploadItem = () => {
    for (const path of event.path) {
      if (path.classList.contains(antUploadItemCls)) {
        return path;
      } else if (path.classList.contains(`${prefixCls}-container`)) {
        return null;
      }
    }
    return null;
  };
  const uploadItem = getUploadItem();
  if (!uploadItem) {
    return;
  }
  const actions = uploadItem.getElementsByClassName('ant-upload-list-item-actions');
  if (!actions || actions.length === 0) {
    return;
  }
  // 添加操作按钮
  const div = document.createElement('div');
  div.className = 'upload-actions-container';
  createApp(UploadItemActions, {
    element: uploadItem,
    fileList: fileList,
    mover: props.mover,
    download: props.download,
    emitValue: emitValue,
  }).mount(div);
  actions[0].appendChild(div);
  uploadItem.setAttribute('data-has-actions', 'true');
  uploadItem.removeEventListener('mouseover', onAddActionsButton);
}

// 解析数据库存储的逗号分割
function parsePathsValue(paths) {
  if (!paths || paths.length == 0) {
    fileList.value = [];
    return;
  }
  let list: any[] = [];
  for (const item of paths.split(',')) {
    let url = getFileAccessHttpUrl(item);
    list.push({
      uid: uidGenerator(),
      name: getFileName(item),
      status: 'done',
      url: url,
      response: { status: 'history', message: item },
    });
  }
  fileList.value = list;
}

// 解析数组值
function parseArrayValue(array) {
  if (!array || array.length == 0) {
    fileList.value = [];
    return;
  }
  let list: any[] = [];
  for (const item of array) {
    let url = getFileAccessHttpUrl(item.filePath);
    list.push({
      uid: uidGenerator(),
      name: item.fileName,
      url: url,
      status: 'done',
      response: { status: 'history', message: item.filePath },
    });
  }
  fileList.value = list;
}

// 文件上传之前的操作
function onBeforeUpload(file) {
  uploadGoOn.value = true;
  if (isImageMode.value) {
    if (file.type.indexOf('image') < 0) {
      createMessage.warning('请上传图片');
      uploadGoOn.value = false;
      return false;
    }
  }
  // 扩展 beforeUpload 验证
  if (typeof props.beforeUpload === 'function') {
    return props.beforeUpload(file);
  }
  return true;
}

// 删除处理事件
function onRemove() {
  if (props.removeConfirm) {
    return new Promise((resolve) => {
      createConfirm({
        title: '删除',
        content: `确定要删除这${isImageMode.value ? '张图片' : '个文件'}吗？`,
        iconType: 'warning',
        onOk: () => resolve(true),
        onCancel: () => resolve(false),
      });
    });
  }
  return true;
}

// upload组件change事件
function onFileChange(info) {
  if (!info.file.status && uploadGoOn.value === false) {
    info.fileList.pop();
  }
  let fileListTemp = info.fileList;
  // 限制最大上传数
  if (props.maxCount > 0) {
    let count = fileListTemp.length;
    if (count >= props.maxCount) {
      let diffNum = props.maxCount - fileListTemp.length;
      if (diffNum >= 0) {
        fileListTemp = fileListTemp.slice(-props.maxCount);
      } else {
        return;
      }
    }
  }
  if (info.file.status === 'done') {
    if (info.file.response.success) {
      fileListTemp = fileListTemp.map((file) => {
        if (file.response) {
          let reUrl = file.response.data.ossPath;
          file.url = getFileAccessHttpUrl(reUrl);
        }
        return file;
      });
    }
  } else if (info.file.status === 'error') {
    createMessage.error(`${info.file.name} 上传失败.`);
  }
  fileList.value = fileListTemp;
  if (info.file.status === 'done' || info.file.status === 'removed') {
    //returnUrl为true时仅返回文件路径
    if (props.returnUrl) {
      handlePathChange();
    } else {
      //returnUrl为false时返回文件名称、文件路径及文件大小
      let newFileList: any[] = [];
      for (const item of fileListTemp) {
        if (item.status === 'done') {
          let fileJson = {
            fileName: item.name,
            filePath: item.response.data.ossPath,
            fileSize: item.size,
          };
          newFileList.push(fileJson);
        }
      }
      emitValue(newFileList);
    }
  }
}

function handlePathChange() {
  let uploadFiles = fileList.value;
  let path = '';
  if (!uploadFiles || uploadFiles.length == 0) {
    path = '';
  }
  let pathList: string[] = [];
  for (const item of uploadFiles) {
    if (item.status === 'done') {
      pathList.push(item.response.data.ossPath);
    } else {
      return;
    }
  }
  if (pathList.length > 0) {
    path = pathList.join(',');
  }
  emitValue(path);
}

// 预览文件、图片
function onFilePreview(file) {
  if (isImageMode.value) {
    //createImgPreview({ imageList: [file.url], maskClosable: true });
  } else {
    window.open(file.url);
  }
}

function emitValue(value) {
  emit('change', value);
  emit('update:value', value);
}

function uidGenerator() {
  return '-' + parseInt(Math.random() * 10000 + 1, 10);
}

function getFileName(path) {
  if (path.lastIndexOf('\\') >= 0) {
    let reg = new RegExp('\\\\', 'g');
    path = path.replace(reg, '/');
  }
  return path.substring(path.lastIndexOf('/') + 1);
}

defineExpose({
  addActionsListener,
});
</script>

<style lang="less">
//noinspection LessUnresolvedVariable
@prefix-cls: ~'@{namespace}-j-upload';

.@{prefix-cls} {
  &-container {
    position: relative;

    .upload-disabled {
      .ant-upload-list-item {
        .anticon-close {
          display: none;
        }

        .anticon-delete {
          display: none;
        }
      }
      /*详情界面 图片下载按钮显示不全*/
      .upload-download-handler {
        right: 6px !important;
      }
    }

    .ant-upload-list-item {
      .upload-actions-container {
        position: absolute;
        top: -31px;
        left: -18px;
        z-index: 11;
        width: 84px;
        height: 84px;
        line-height: 28px;
        text-align: center;
        pointer-events: none;

        a {
          opacity: 0.9;
          margin: 0 5px;
          cursor: pointer;
          transition: opacity 0.3s;

          .anticon {
            color: #fff;
            font-size: 16px;
          }

          &:hover {
            opacity: 1;
          }
        }

        .upload-mover-handler,
        .upload-download-handler {
          position: absolute;
          pointer-events: auto;
        }

        .upload-mover-handler {
          width: 100%;
          bottom: 0;
        }

        .upload-download-handler {
          top: -4px;
          right: -4px;
        }
      }
    }
  }
}
</style>
